using System;

using inf = Anycmd.Xacml.Interfaces;
using rtm = Anycmd.Xacml.Runtime;

namespace Anycmd.Xacml.Runtime.Functions
{
	/// <summary>
	/// 
	/// </summary>
	public abstract class BaseOneAndOnly : FunctionBase, inf.ITypeSpecificFunction
	{
		#region IFunction Members

		/// <summary>
		/// Gets the value as a generic object for the specified element.
		/// </summary>
		/// <param name="element">The element to get the value from.</param>
		/// <returns></returns>
		protected object GetTypedValue( inf.IFunctionParameter element )
		{
			if (element == null) throw new ArgumentNullException("element");
			return element.GetTypedValue( DataType, 0 );
		}

		/// <summary>
		/// Evaluates the function.
		/// </summary>
		/// <param name="context">The evaluation context instance.</param>
		/// <param name="args">The function arguments.</param>
		/// <returns>The result value of the function evaluation.</returns>
		public override Anycmd.Xacml.Runtime.EvaluationValue Evaluate( rtm.EvaluationContext context, params inf.IFunctionParameter[] args )
		{
			if (context == null) throw new ArgumentNullException("context");
			if (args == null) throw new ArgumentNullException("args");
			if( args[0].IsBag && args[0].BagSize == 1 )
			{
				inf.IFunctionParameter attrib = (inf.IFunctionParameter)args[0].Elements[0];
				return new EvaluationValue( GetTypedValue( attrib ), DataType );
			}
			else
			{
				return EvaluationValue.Indeterminate;
			}
		}

		/// <summary>
		/// The data type of the return value.
		/// </summary>
		public override Anycmd.Xacml.Interfaces.IDataType Returns
		{
			get{ return DataType; }
		}

		/// <summary>
		/// Defines the data types for the function arguments.
		/// </summary>
		public override Anycmd.Xacml.Interfaces.IDataType[] Arguments
		{
			get
			{
				return new Anycmd.Xacml.Interfaces.IDataType[]{ DataTypeDescriptor.Bag };
			}
		}

		/// <summary>
		/// Defines the data type for which the function was defined for.
		/// </summary>
		public abstract Anycmd.Xacml.Interfaces.IDataType DataType { get; }

		#endregion
	}
}
